<?php
namespace app\command;

use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\facade\Db;
use app\service\OssService;
use app\service\TopviewApiService;

class MigrateVoiceResources extends Command
{
    protected function configure()
    {
        $this->setName('migrate:voice')
            ->setDescription('迁移语音资源到OSS');
    }

    protected function execute(Input $input, Output $output)
    {
        $output->writeln('开始迁移语音资源到OSS...');
        
        try {
            $migrator = new VoiceResourceMigrator($output);
            $result = $migrator->migrate();
            
            $output->writeln("迁移完成！处理了 {$result['processed']} 个语音，成功 {$result['success']} 个，失败 {$result['failed']} 个");
            
        } catch (\Exception $e) {
            $output->writeln("迁移过程中发生错误: " . $e->getMessage());
            return 1; // 返回错误状态码
        }
        
        return 0; // 返回成功状态码
    }
}

class VoiceResourceMigrator
{
    private $ossService;
    private $apiService;
    private $output;
    private $failedUrls = []; // 记录失败的URL
    
    public function __construct(Output $output)
    {
        $this->output = $output;
        $this->ossService = new OssService();
        $this->apiService = new TopviewApiService();
    }
    
    /**
     * 主执行方法
     */
    public function migrate()
    {
        $pageNo = 1;
        $pageSize = 50; // 每页数量
        $totalProcessed = 0;
        $successCount = 0;
        $failedCount = 0;
        
        do {
            $this->output->writeln("正在处理第 {$pageNo} 页...");
            
            // 获取语音列表
            try {
                $response = $this->apiService->getVoiceList($pageNo, $pageSize, 'en', '', '', '');
            } catch (\Exception $e) {
                $this->output->writeln("获取数据失败: " . $e->getMessage());
                break;
            }
            
            if (!$response || !isset($response['data'])) {
                $this->output->writeln("获取数据失败，跳过第 {$pageNo} 页");
                break;
            }
            
            $voices = $response['data'] ?? [];
            $hasMore = count($voices) > 0;
            
            foreach ($voices as $voice) {
                $result = $this->processVoice($voice);
                $totalProcessed++;
                
                if ($result) {
                    $successCount++;
                } else {
                    $failedCount++;
                }
            }
            
            $pageNo++;
            
            // 防止请求过快
            sleep(2);
            
        } while ($hasMore);
        
        // 生成迁移报告
        $this->generateReport();
        
        return [
            'processed' => $totalProcessed,
            'success' => $successCount,
            'failed' => $failedCount
        ];
    }
    
    /**
     * 处理单个语音
     */
    private function processVoice($voice)
    {
        $voiceId = $voice['voiceId'] ?? '';
        $originalDemoUrl = $voice['demoAudioUrl'] ?? '';
        
        if (empty($voiceId) || empty($originalDemoUrl)) {
            $this->output->writeln("  跳过无效语音数据: {$voiceId}");
            return false;
        }
        
        $this->output->writeln("  处理语音: {$voiceId}");
        
        // 检查是否已经成功迁移
        $existing = Db::table('voice_resources')
            ->where('voice_id', $voiceId)
            ->find();
            
        if ($existing && $existing['status'] == 1) {
            $this->output->writeln("    语音已迁移，跳过");
            return true;
        }
        
        try {
            // 如果记录存在但未成功，先更新为迁移中状态
            if ($existing) {
                $this->output->writeln("    重新尝试迁移");
                Db::table('voice_resources')
                    ->where('voice_id', $voiceId)
                    ->update([
                        'status' => 0, // 迁移中
                        'update_time' => time()
                    ]);
            } else {
                // 记录开始迁移
                $this->recordMigrationStart($voiceId, $originalDemoUrl);
            }
            
            // 处理音频
            $newDemoUrl = $this->migrateResource(
                $originalDemoUrl, 
                "voice/{$voiceId}/demo.mp3"
            );
            
            // 更新迁移结果
            $this->recordMigrationSuccess($voiceId, $newDemoUrl);
            
            $this->output->writeln("    ✅ 迁移完成");
            return true;
            
        } catch (\Exception $e) {
            $this->output->writeln("    ❌ 迁移失败: " . $e->getMessage());
            $this->recordMigrationFailure($voiceId, $e->getMessage());
            return false;
        }
    }
    
    /**
     * 迁移单个资源
     */
    private function migrateResource($originalUrl, $ossPath)
    {
        // 检查是否已经是OSS地址
        if (strpos($originalUrl, 'aliyuncs.com') !== false) {
            $this->output->writeln("    资源已在OSS上，跳过: {$ossPath}");
            return $originalUrl;
        }
        
        $this->output->writeln("    下载: " . basename($ossPath));
        
        // 下载文件到临时目录
        $tempFile = $this->downloadFile($originalUrl);
        if (!$tempFile) {
            throw new \Exception("下载文件失败: {$originalUrl}");
        }
        
        try {
            // 上传到OSS
            $this->output->writeln("    上传到OSS: {$ossPath}");
            $ossUrl = $this->ossService->putObject($ossPath, $tempFile);
            
            // 删除临时文件
            unlink($tempFile);
            
            return $ossUrl;
            
        } catch (\Exception $e) {
            // 删除临时文件
            if (file_exists($tempFile)) {
                unlink($tempFile);
            }
            throw $e;
        }
    }
    
    /**
     * 下载文件到本地临时目录
     */
    private function downloadFile($url)
    {
        // 创建临时目录
        $tempDir = runtime_path() . 'temp/voice_migration';
        if (!is_dir($tempDir)) {
            mkdir($tempDir, 0755, true);
        }
        
        // 生成临时文件名
        $extension = pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION);
        $tempFile = $tempDir . '/' . uniqid() . '.' . ($extension ?: 'tmp');
        
        // 使用curl下载
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
        curl_setopt($ch, CURLOPT_TIMEOUT, 120);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36');
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        
        // 检查是否有代理设置
        $proxy = getenv('https_proxy') ?: getenv('http_proxy');
        if ($proxy) {
            curl_setopt($ch, CURLOPT_PROXY, $proxy);
            curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
        }
        
        $data = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        
        // 检查HTTP状态码
        if (!in_array($httpCode, [200, 206]) || !$data) {
            if ($error) {
                $this->output->writeln("    下载失败: {$error}");
            } else {
                $this->output->writeln("    下载失败，HTTP状态码: {$httpCode}");
            }
            return false;
        }
        
        // 保存到临时文件
        if (file_put_contents($tempFile, $data) === false) {
            $this->output->writeln("    保存临时文件失败");
            return false;
        }
        
        return $tempFile;
    }
    
    /**
     * 记录迁移开始
     */
    private function recordMigrationStart($voiceId, $originalDemoUrl)
    {
        $time = time();
        
        $data = [
            'voice_id' => $voiceId,
            'original_demo_url' => $originalDemoUrl,
            'status' => 0, // 迁移中
            'create_time' => $time,
            'update_time' => $time
        ];
        
        // 使用普通insert，因为已经检查过不存在重复记录
        Db::table('voice_resources')
            ->insert($data);
    }
    
    /**
     * 记录迁移成功
     */
    private function recordMigrationSuccess($voiceId, $ossDemoUrl)
    {
        Db::table('voice_resources')
            ->where('voice_id', $voiceId)
            ->update([
                'oss_demo_url' => $ossDemoUrl,
                'status' => 1, // 已迁移
                'update_time' => time()
            ]);
    }
    
    /**
     * 记录迁移失败
     */
    private function recordMigrationFailure($voiceId, $errorMsg)
    {
        Db::table('voice_resources')
            ->where('voice_id', $voiceId)
            ->update([
                'status' => 2, // 迁移失败
                'update_time' => time()
            ]);
            
        // 记录到日志
        trace("Voice migration failed - ID: {$voiceId}, Error: {$errorMsg}", 'error');
    }
    
    /**
     * 生成迁移报告
     */
    private function generateReport()
    {
        // 统计无法访问的资源
        $failedUrls = $this->failedUrls;
        $failedCount = count($failedUrls);
        
        if ($failedCount > 0) {
            $this->output->writeln("以下资源无法访问，请检查网络连接或资源可用性：");
            foreach ($failedUrls as $url) {
                $this->output->writeln("  - {$url}");
            }
        } else {
            $this->output->writeln("所有资源均可访问，迁移成功！");
        }
    }
} 